package code.example.base.util.concurrent.container.blockinglist;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

public class BlockingListByLock<E> implements BlockingList<E> {
    static final int MAXIMUM_CAPACITY = 1 << 30;
    int tableSizeFor(int cap) {
        int n = cap - 1;
        n |= n >>> 1;
        n |= n >>> 2;
        n |= n >>> 4;
        n |= n >>> 8;
        n |= n >>> 16;
        return (n < 0) ? 1 : (n >= MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : n + 1;
    }

    Object items[]= null;
    volatile  int count = 0;
    int putIndex =0;
    int takeIndex = 0;

    ReentrantLock lock = new ReentrantLock();
    Condition full = lock.newCondition();
    Condition emtpy = lock.newCondition();

    public BlockingListByLock(int capacity){
        int size = tableSizeFor(capacity);
        items = new Object [size];
    }

    @Override
    public void put(E e) throws InterruptedException {
        lock.lock();
        try{
            while(count ==items.length){
                full.await();
            }
            putIndex ++;
            putIndex = putIndex & (items.length-1);
            items[putIndex]= e;
            count++;
            emtpy.signal();
        }finally {
            lock.unlock();
        }
    }

    @Override
    public E take() throws InterruptedException {
        lock.lock();
        try{
            while(count ==0){
                emtpy.await();
            }
            takeIndex ++;
            takeIndex = takeIndex & (items.length-1);
            count--;
            E e = (E)items[takeIndex];
            items[takeIndex] = null;
            full.signal();
            return e;
        }finally {
            lock.unlock();
        }
    }

    @Override
    public int size() {
        return count;
    }
}
